package com.tcfvic.client.panels.widgets.widgetcontents;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.tcfvic.client.PersonService;
import com.tcfvic.client.PersonServiceAsync;
import com.tcfvic.client.panels.widgets.SimpleMessagePopup;
import com.tcfvic.client.panels.widgets.TCFWidgetContent;
import com.tcfvic.client.pojos.Expense;
import com.tcfvic.client.pojos.ExpenseId;
import com.tcfvic.client.pojos.Fundingsource;
import com.tcfvic.client.pojos.Person;
import com.tcfvic.client.pojos.Personcourse;
import com.tcfvic.client.tools.Tools;

public class ExpensesTab extends AbstractDataEntryWidgets implements
		TCFWidgetContent {

	private final PersonServiceAsync personService = GWT
			.create(PersonService.class);
	private List<Personcourse> personCourses = new ArrayList<Personcourse>();
	private List<Fundingsource> fs = new ArrayList<Fundingsource>();

	private FlexTable expensesTable = null;
	private FlexTable tabContentFlexTable = null;
	private Button addExpenseButton = new Button("Add new expense");

	private int rowId = 0;
	private String currentPersonRowId = "";

	@Override
	public void clear() {
		while (expensesTable.getRowCount() > 1) {
			expensesTable.removeRow(1);
		}
	}

	@Override
	public Widget getContent() {
		tabContentFlexTable = new FlexTable();
		tabContentFlexTable.setCellSpacing(3);
		tabContentFlexTable.setWidth("100%");

		setupExpensesList();
		tabContentFlexTable.setWidget(1, 0, expensesTable);
		tabContentFlexTable.getFlexCellFormatter().setColSpan(1, 0, 4);

		// Add new expense button
		addExpenseButton.getElement().setId("addExpenseButton");
		tabContentFlexTable.setWidget(2, 0, addExpenseButton);

		addExpenseButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				addExpense(0, null, "", "", -1, "", null);
			}
		});

		// SAVE button
		saveButton.getElement().setId("saveButton");
		tabContentFlexTable.setWidget(3, 0, saveButton);

		return tabContentFlexTable;
	}

	public void setupExpensesList() {
		// Create a Flex Table
		int col = 0;
		expensesTable = new FlexTable();
		expensesTable.addStyleName("cw-FlexTable");
		expensesTable.setWidth("32em");
		expensesTable.setCellSpacing(1);
		expensesTable.setCellPadding(1);
		col++; // increase cause ID column is 0
		expensesTable.setHTML(0, col++, "Date");
		expensesTable.setHTML(0, col++, "Related course");
		expensesTable.setHTML(0, col++, "Description");
		expensesTable.setHTML(0, col++, "Funding source");
		expensesTable.setHTML(0, col++, "Amount");
//		expensesTable.setHTML(0, col++, "Amount Unit");
	}

	public void addExpense(Integer expenseId, Date date, String description,
			String relatedCourse, int fs, String unit, Double amount) {
		final int numRows = expensesTable.getRowCount();
		TextBox dateTB = new TextBox();
		dateTB.setText(Tools.formatDate(date));
		TextBox amountTB = new TextBox();
		try {
			amountTB.setText(amount.toString());
		} catch (Exception e) {
		}

		int col = 0;
		Widget idWidget = new HTML(++rowId + idDelimiter + expenseId);
		idWidget.setVisible(false);
		expensesTable.setWidget(numRows, col++, idWidget);
		expensesTable.setWidget(numRows, col++, dateTB);
		ListBox lb = new ListBox();
		expensesTable.setWidget(numRows, col++, getPersonCoursesListBox(lb));
		lb.setSelectedIndex(Tools.getSelectedIndexBasedOnItem(lb, relatedCourse));
		lb = getDescriptionListBox();
		lb.setSelectedIndex(Tools.getSelectedIndex(lb, description));
		expensesTable.setWidget(numRows, col++, lb);
		lb = new ListBox();
		expensesTable.setWidget(numRows, col++, getFSListBox(lb));
		lb.setSelectedIndex(Tools.getSelectedIndexBasedOnItem(lb, String
				.valueOf(fs)));
		expensesTable.setWidget(numRows, col++, amountTB);
//		lb = new ListBox();
//		expensesTable.setWidget(numRows, col++, getUnitListBox(lb));
//		lb.setSelectedIndex(Tools.getSelectedIndexBasedOnItem(lb, String
//				.valueOf(unit)));

		Hyperlink link = new Hyperlink("Remove", String.valueOf(rowId)
				+ idDelimiter + expenseId);
		link.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				Hyperlink link = (Hyperlink) event.getSource();
				removeRow(link.getTargetHistoryToken());
			}
		});
		expensesTable.setWidget(numRows, 7, link);
	}

	private ListBox getDescriptionListBox() {
		ListBox lb = new ListBox();
		lb.addItem("", "");
		lb.addItem("Course fees", "Course fees");
		lb.addItem("Equipment", "Equipment");
		lb.addItem("Travel", "Travel");
		lb.addItem("Computer", "Computer");
		return lb;
	}

	private ListBox getPersonCoursesListBox(final ListBox lb) {
		lb.addItem("", "");
		for (Personcourse pc : personCourses) {
			lb.addItem(pc.getCourse().getName(), String.valueOf(pc.getCourse().getId()));
		}
		return lb;
	}

	private ListBox getFSListBox(final ListBox lb) {
		lb.addItem("", "");
		for (Fundingsource pfs : fs) {
			lb.addItem(pfs.getSourceName(), String
					.valueOf(pfs.getId()));
		}
		return lb;
	}

	@SuppressWarnings("unused")
	private ListBox getUnitListBox(final ListBox lb) {
		lb.addItem("", "");
		lb.addItem("Dollars", "Dollars");
		lb.addItem("Hours", "Hours");
		lb.addItem("Days", "Days");
		lb.addItem("No courses", "No courses");
		return lb;
	}

	private void removeRow(String id) {
		for (int i = 1; i < expensesTable.getRowCount(); i++) {
			HTML rowID = (HTML) expensesTable.getWidget(i, 0);
			if (rowID.getText().equals(id)) {
				expensesTable.removeRow(i);
				break;
			}
		}
	}

	@Override
	public String getName() {
		return "Expenses";
	}

	private void getAllExpenses() {
		personService.getAllExpenses(Integer.valueOf(currentPersonRowId),
				new AsyncCallback<List<Expense>>() {
					@Override
					public void onSuccess(List<Expense> result) {
						populateExpensesList(result);
					}

					@Override
					public void onFailure(Throwable caught) {
						new SimpleMessagePopup(
								"Error occured getting the training list "
										+ caught, null).showPopup();
						GWT.log("Error occured getting the training list: "
								+ caught + "!---", caught);
						System.err
								.println("Error occured getting the training list"
										+ caught);
					}
				});
	}

	@Override
	public void initialise() {
		personCourses.clear();
		if (!currentPersonRowId.isEmpty()) {
			personService.getPersonCourseDetails(Integer
					.parseInt(currentPersonRowId),
					new AsyncCallback<List<Personcourse>>() {
						@Override
						public void onSuccess(List<Personcourse> result) {
							if (result != null) {
								personCourses.addAll(result);
							}
							getFundingSources();
						}

						@Override
						public void onFailure(Throwable caught) {
							new SimpleMessagePopup(
									"Error occured getting the courses the person is enroled in "
											+ caught, null).showPopup();
							GWT.log(
									"Error occured getting the courses the person is enroled in: "
											+ caught + "!---", caught);
						}
					});
		}

	}

	public void getFundingSources() {
		fs.clear();
		personService.getPersonFundingSources(Integer
				.parseInt(currentPersonRowId),
				new AsyncCallback<List<Fundingsource>>() {
					@Override
					public void onSuccess(List<Fundingsource> result) {
						if (result != null) {
							fs.addAll(result);
						}
						getAllExpenses();
					}

					@Override
					public void onFailure(Throwable caught) {
						new SimpleMessagePopup(
								"Error occured getting the funding sources for the person "
										+ caught, null).showPopup();
						GWT.log(
								"Error occured getting the funding sources for the person: "
										+ caught + "!---", caught);
					}
				});
	}

	public void populateExpensesList(List<Expense> expenses) {
		if (expenses != null) {
			Double total = 0.0;
			for (Expense expense : expenses) {
				int fsId = 0;
				if (expense.getFundingsource() != null) {
					fsId = expense.getFundingsource().getId();
				}
				addExpense(0, expense.getDate(), expense.getDescription(),
						expense.getRelatedCourse(), fsId, expense.getUnits(),
						expense.getAmount());
				if (expense.getAmount() != null) {
					total += expense.getAmount();
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T saveContent(T t) throws Exception {
		List<Expense> expenses = new ArrayList<Expense>();
		if (t == null || !(t instanceof Person)) {
			GWT.log("Expenses not saved due to not receiving Person details.",
					null);
			return null;
		}
		Person person = (Person) t;
		if (expensesTable.getRowCount() > 1) {
			for (int i = 1; i < expensesTable.getRowCount(); i++) {
				Expense expense = new Expense();
				expense.setId(new ExpenseId(i, person.getId()));
				String date = ((TextBox) expensesTable.getWidget(i, 1))
						.getText();
				ListBox lb = (ListBox) expensesTable.getWidget(i, 2);
				String relatedCourse = lb.getValue(lb.getSelectedIndex());
				lb = (ListBox) expensesTable.getWidget(i, 3);
				String description = lb.getItemText(lb.getSelectedIndex());
				lb = (ListBox) expensesTable.getWidget(i, 4);
				String relatedFS = lb.getValue(lb.getSelectedIndex());
				String amount = ((TextBox) expensesTable.getWidget(i, 5))
						.getText();
//				lb = (ListBox) expensesTable.getWidget(i, 6);
//				String unit = lb.getValue(lb.getSelectedIndex());
				if (date != null && date.trim().length() > 0) {
					try {
						expense.setDate(Tools.parseDate(date));
					} catch (Exception e) {
						throw new Exception("The date you entered(" + date
								+ ") needs to be in the format dd/mm/yyyy");
					}
				}
				expense.setDescription(description);
				expense.setRelatedCourse(relatedCourse);

				if (relatedFS != null && !relatedFS.isEmpty()) {
					Fundingsource fs = new Fundingsource();
					fs.setId(Integer.valueOf(relatedFS));
					expense.setFundingsource(fs);
				}
				try {
					expense.setAmount(Double.parseDouble(amount));
//					expense.setUnits(unit);
				} catch (Exception e) {
					throw new Exception("You didn't enter a valid amount");
				}
				expenses.add(expense);
			}
			personService.saveExpenses(expenses, true, new AsyncCallback<Void>() {

				@Override
				public void onFailure(Throwable caught) {
					GWT.log("Error saving expenses", caught);

				}

				@Override
				public void onSuccess(Void result) {
					clear();
					initialise();
				}
			});
		}
		return (T) person;
	}

	@Override
	public void updateContent(Object o) {
		if (o != null) {
			rowId = 0;
			Person p = (Person) o;
			currentPersonRowId = String.valueOf(p.getId());
			initialise();
		}
	}

	@Override
	public void createNewRecord() {
		// TODO Auto-generated method stub

	}

}
